﻿using gt.dotnetcore.webapi.extension.Entity;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Internal;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Text;
using System.Threading.Tasks;

namespace gt.dotnetcore.webapi.extension.Middlewares
{
    public class GlobalApiLoggingMiddleware : IMiddleware
    {
        private readonly ILogger _logger;

        public GlobalApiLoggingMiddleware(ILogger<GlobalApiLoggingMiddleware> logger)
        {
            _logger = logger;
        }

        public async Task InvokeAsync(HttpContext context, RequestDelegate next)
        {
            Stopwatch watch = new Stopwatch();
            watch.Start();

            //reuqest支持buff,否则body只能读取一次
            context.Request.EnableBuffering();
            //这里不要释放stream,否则后续读取request.body会报错
            var reader = new StreamReader(context.Request.Body, Encoding.UTF8);
            var requestStr = reader.ReadToEnd();
            context.Request.Body.Position = 0;

            Stream originalBody = context.Response.Body;

            try
            {
                using (var memStream = new MemoryStream())
                {
                    context.Response.Body = memStream;
                    await next.Invoke(context);

                    var request = context.Request;
                    var log = new ApiLogEntity()
                    {
                        Appkey = request.GetAppkey(),
                        ClientIp = request.GetClientRealIp(),
                        HttpMethod = request.Method,
                        Request = requestStr,
                        RequestId = request.GetRequestId(),
                        RequestUrl = request.Path.Value,
                        QueryString = request.QueryString.Value,
                        ServerIp = request.Host.Value,
                        StatusCode = context.Response.StatusCode,
                        Duration = watch.ElapsedMilliseconds
                    };

                    memStream.Position = 0;
                    log.Response = new StreamReader(memStream).ReadToEnd();

                    memStream.Position = 0;
                    await memStream.CopyToAsync(originalBody);

                    _logger.LogInformation(JsonConvert.SerializeObject(log));
                }
            }
            finally
            {
                //重新给response.body赋值，用于返回
                context.Response.Body = originalBody;
                watch.Stop();
            }
        }
    }
}
